#pragma once
#include <math.h>
#include "btBulletDynamicsCommon.h"

class Vector3 {

private:
	float entry[3];

public:
	Vector3() { entry[0]=0.0; entry[1]=0.0f; entry[2]=0.0f;};
	Vector3(const Vector3& v) {
		for (int i=0; i<3; i++) 
			entry[i]=v.entry[i];
	};
	Vector3(const btVector3& v) {
		for (int i=0; i<3; i++) 
			entry[i]=v[i];
	};
	Vector3(float x, float y, float z) { entry[0]=x; entry[1]=y; entry[2]=z;};
	~Vector3() {};

	const float& x() const { return entry[0]; };
	const float& y() const { return entry[1]; };
	const float& z() const { return entry[2]; };

	float& x() { return entry[0]; };
	float& y() { return entry[1]; };
	float& z() { return entry[2]; };

	const float length() const {
		BT_PROFILE("Vector3::length");
		return sqrt(x()*x() + y()*y() + z()*z());
	}
	const Vector3 normalized() {
		return *this/length();
	}
	const Vector3& normalize() {
		return (*this/=length());
	}

#define _VECTOR3_OPERATOR
#ifdef _VECTOR3_OPERATOR

	const float operator[] (int index) const {
		return entry[index];
	};
	float &operator[] (int index) {
		return entry[index];
	};

	Vector3& operator = (const btVector3& v) {
		entry[0]=v.x();
		entry[1]=v.y();
		entry[2]=v.z();
		return *this;
	}
	Vector3& operator = (const Vector3& v) {
		entry[0]=v.x();
		entry[1]=v.y();
		entry[2]=v.z();
		return *this;
	}
	Vector3 operator * (const float& f) {
		Vector3 temp = *this;
		for (int i=0; i<3; i++)
			temp.entry[i] *= f;
		return temp;
	} 
	Vector3 operator *= (const float& f) {
		for (int i=0; i<3; i++)
			entry[i] *= f;
		return *this;
	} 
	Vector3 operator * (const int& n) {
		Vector3 temp = *this;
		for (int i=0; i<3; i++)
			temp.entry[i] *= n;
		return temp;
	}
	Vector3 operator / (const float& f) {
		Vector3 temp = *this;
		for (int i=0; i<3; i++)
			temp.entry[i] /= f;
		return temp;
	}
	Vector3& operator /= (const float& f) {
		for (int i=0; i<3; i++)
			entry[i] /= f;
		return *this;
	}
	Vector3 operator + (const Vector3& v) {
		Vector3 temp = *this;
		for (int i=0; i<3; i++)
			temp.entry[i] += v[i];
		return temp;
	}
	Vector3 operator + (const btVector3& v) {
		Vector3 temp = *this;
		for (int i=0; i<3; i++)
			temp.entry[i] += v[i];
		return temp;
	}
	Vector3 operator - (const Vector3& v) {
		Vector3 temp = *this;
		for (int i=0; i<3; i++)
			temp.entry[i] -= v[i];
		return temp;
	}
	Vector3 operator - (const btVector3& v) {
		Vector3 temp = *this;
		for (int i=0; i<3; i++)
			temp.entry[i] -= v[i];
		return temp;
	}
	Vector3 operator * (const Vector3& v) {		// not Dot Product (x1*x2, y1*y2, z1*z2)
		return Vector3(x() * v.x(), y() * v.y(), z() * v.z());
	}
	Vector3 operator * (const btVector3& v) {	
		return Vector3(x() * v.x(), y() * v.y(), z() * v.z());
	}
	Vector3 operator / (const Vector3& v) {	
		return Vector3(x() / v.x(), y() / v.y(), z() / v.z());
	}
	Vector3& operator += (const Vector3& v) {
		for (int i=0;i<3;i++)
			entry[i] += v[i];
		return *this;
	}
	Vector3& operator -= (const Vector3& v) {
		for (int i=0;i<3;i++)
			entry[i] -= v[i];
		return *this;
	}
#endif

	const float dot(const Vector3& v1) const {
		return entry[0] * v1[0] + entry[1] * v1[1] + entry[2] * v1[2];
	};
	static const float dot(const Vector3& v1, const Vector3& v2)  {
		return v2[0] * v1[0] + v2[1] * v1[1] + v2[2] * v1[2];
	};

	operator btVector3() {
		return btVector3(x(), y(), z());
	}
	operator btVector3() const {
		return btVector3(x(), y(), z());
	}
};
